package com.example.util;

import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ShellExecutor {

    public record ExecuteResult(int exitCode, String output, String error) {
    }

    /**
     * 执行Shell命令的通用方法
     * @param command 命令参数列表（避免空格解析问题）
     * @param timeoutSeconds 超时时间（秒）
     * @param workDir 工作目录（null表示当前目录）
     * @param envVars 环境变量（null表示继承当前环境）
     * @param charset 字符集（推荐根据系统指定，如 StandardCharsets.UTF_8）
     */
    public static ExecuteResult executeCommand(List<String> command, int timeoutSeconds,
                                               File workDir, Map<String, String> envVars,
                                               Charset charset) throws IOException, InterruptedException {
        ProcessBuilder pb = new ProcessBuilder(command);

        // 设置工作目录
        if (workDir != null) {
            pb.directory(workDir);
        }

        // 设置环境变量
        if (envVars != null) {
            Map<String, String> processEnv = pb.environment();
            processEnv.putAll(envVars);
        }

        // 合并错误流到标准输出（可选）
        // pb.redirectErrorStream(true);

        Process process = pb.start();
        StringBuilder output = new StringBuilder();
        StringBuilder error = new StringBuilder();

        // 多线程读取输出和错误流（防止阻塞）
        Thread outputThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), charset))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            } catch (IOException e) {
                LogUtil.logError(e.toString(), e);
            }
        });

        Thread errorThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getErrorStream(), charset))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    error.append(line).append("\n");
                }
            } catch (IOException e) {
                LogUtil.logError(e.toString(), e);
            }
        });

        outputThread.start();
        errorThread.start();

        boolean finished = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
        if (!finished) {
            process.destroyForcibly();
            throw new InterruptedException("Command timed out after " + timeoutSeconds + " seconds");
        }

        outputThread.join();
        errorThread.join();

        return new ExecuteResult(
                process.exitValue(),
                output.toString().trim(),
                error.toString().trim()
        );
    }

// 示例用法
//    public static void main(String[] args) {
//        List<String> command = new ArrayList<>();
//        if (System.getProperty("os.name").toLowerCase().contains("win")) {
//            command.add("cmd");
//            command.add("/c");
//            command.add("dir");
//        } else {
//            command.add("bash");
//            command.add("-c");
//            command.add("ls -l");
//        }
//
//        try {
//            ExecuteResult result = executeCommand(
//                    command,
//                    30,
//                    new File("."),
//                    Map.of("MY_ENV", "test_value"),
//                    Charset.defaultCharset()
//            );
//
//            System.out.println("Exit Code: " + result.exitCode);
//            System.out.println("Output:\n" + result.output);
//            System.out.println("Error:\n" + result.error);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
}
